/**
 * Created by Administrator on 2016/10/8.
 */

/**
 * Create a new object and copy all properties in an exist object to the new object
 * @function
 * @param {object|Array|cc.Node} obj The source object
 * @return {Array|object|cc.Node} The created object
 */
jGame.clone = function (obj) {

    // Cloning is better if the new object is having the same prototype chain
    // as the copied obj (or otherwise, the cloned object is certainly going to
    // have a different hidden class). Play with C1/C2 of the
    // PerformanceVirtualMachineTests suite to see how this makes an impact
    // under extreme conditions.
    //
    // Object.create(Object.getPrototypeOf(obj)) doesn't work well because the
    // prototype lacks a link to the constructor (Carakan, V8) so the new
    // object wouldn't have the hidden class that's associated with the
    // constructor (also, for whatever reasons, utilizing
    // Object.create(Object.getPrototypeOf(obj)) + Object.defineProperty is even
    // slower than the original in V8). Therefore, we call the constructor, but
    // there is a big caveat - it is possible that the this.init() in the
    // constructor would throw with no argument. It is also possible that a
    // derived class forgets to set "constructor" on the prototype. We ignore
    // these possibities for and the ultimate solution is a standardized
    // Object.clone(<object>).

    if(((typeof obj) === "object") && obj && (obj instanceof cc.Node)) {

        var newObj
        if(typeof obj["_createJGameInstance"] === "function") {
            newObj = obj["_createJGameInstance"]();
            newObj._copyJGameProperties(obj);
            newObj._copyJGameChildren(obj);
        } else {
            newObj = (obj.constructor) ? new obj.constructor : {};
            if(typeof newObj["_copyProperties"] === "function")newObj["_copyProperties"](obj);
            if(typeof newObj["_copyClonedWidgetChildren"] === "function")newObj["_copyClonedWidgetChildren"](obj);
        }
        return newObj;

    } else {

        var newObj = (obj.constructor) ? new obj.constructor : {};

        // Assuming that the constuctor above initialized all properies on obj, the
        // following keyed assignments won't turn newObj into dictionary mode
        // becasue they're not *appending new properties* but *assigning existing
        // ones* (note that appending indexed properties is another story). See
        // CCClass.js for a link to the devils when the assumption fails.
        for (var key in obj) {
            var copy = obj[key];
            // Beware that typeof null == "object" !
            if (((typeof copy) === "object") && copy &&
                !(copy instanceof cc.Node) && !(copy instanceof HTMLElement)) {
                newObj[key] = jGame.clone(copy);
            } else {
                newObj[key] = copy;
            }
        }
        return newObj;

    }
};


jGame.ergodicAllNode = function (root, beforCallback, afterCallback) {
    if(!root || !(root instanceof cc.Node)) return null;

    for (var viewIndex in root.getChildren()) {
        var child = root.getChildren()[viewIndex];
        if(typeof beforCallback === "function")beforCallback(child);
        jGame.ergodicAllNode(child, beforCallback, afterCallback);
        if(typeof afterCallback === "function")afterCallback(child);
    }
};

jGame.findView = function (root, name, userData, classType) {
    if(!name || name == "") return null;
    var scene = root;
    if(name == ".") return scene;
    if(!scene) return null;

    var viewNames = name.split(".");
    var currentView = scene;
    for (var viewNameIndex in viewNames) {
        var viewName = viewNames[viewNameIndex];
        if(viewName == "")continue;
        var view = jGame.findChildView(currentView, viewName);
        if(view) {
            currentView = view;
        }else {
            if(!(currentView.getName() == name)){
                return null;
            }
        }
    }
    if(currentView && classType) {
        var view = jGame.findChildViewForClass(currentView, classType);
        if(view) {
            currentView = view;
        }else {
            if(!(currentView instanceof classType)){
                return null;
            }
        }
    }
    if(currentView && typeof userData != "undefined") {
        currentView = null;
        var currentViews = [scene];
        var lastViewName = viewNames[viewNames.length - 1];
        for (var viewNameIndex in viewNames) {
            var viewName = viewNames[viewNameIndex];
            if(viewName == "")continue;
            var findNextRootView = [];
            for (var rIndex in currentViews) {
                var views = jGame.findChildViews(currentViews[rIndex], viewName);
                findNextRootView = findNextRootView.concat(views);
            }
            currentViews = findNextRootView;
            if(viewName == lastViewName) {
                for(var cIndex in currentViews) {
                    if("" + currentViews[cIndex].getUserData() == "" + userData) {
                        currentView = currentViews[cIndex];
                        break;
                    }
                }
            }
        }
    }
    return currentView;
};

jGame.findChildView = function (root, name) {
    if(!root) return null;
    for (var viewIndex in root.getChildren()) {
        var child = root.getChildren()[viewIndex];
        if(child.getName() == name){
            return child;
        }
        var result = jGame.findChildView(child, name);
        if(result) {
            return result;
        }
    }
    return null;
};

jGame.findChildViews = function (root, name, children) {
    if(!root) return children;
    var result = children;
    if(!result)result = [];
    for (var viewIndex in root.getChildren()) {
        var child = root.getChildren()[viewIndex];
        if(child.getName() == name){
            result.push(child);
        }
        result = jGame.findChildViews(child, name, result);
    }
    return result;
}

jGame.findChildViewForClass = function (root, classType) {
    if(!root || typeof classType != "function") return null;
    for (var viewIndex in root.getChildren()) {
        var child = root.getChildren()[viewIndex];
        if(child instanceof classType){
            return child;
        }
        var result = jGame.findChildViewForClass(child, classType);
        if(result) {
            return result;
        }
    }
    return null;
};

jGame.setAllChildrenController = function (root, controller) {
    if (!root || !(root instanceof cc.Node)) return;
    if (typeof root["setController"] === "function")root["setController"](controller);
    for (var viewIndex in root.getChildren()) {
        var child = root.getChildren()[viewIndex];
        jGame.setAllChildrenController(child, controller);
    }
};

jGame.getAutoLineText = function (ui_text, text_string, limit_width) {
    if(ui_text instanceof jGame.Text && typeof text_string === "string" && typeof limit_width) {
        var isIgnore = ui_text.isIgnoreContentAdaptWithSize();
        ui_text.setString(text_string);
        ui_text.ignoreContentAdaptWithSize(true);
        var width = ui_text.width;
        var lineNumber = Math.ceil(width/limit_width);
        var result = text_string;
        if(lineNumber > 1) {
            var lineLength = Math.floor(text_string.length*limit_width/width);
            result = "";
            for (var i = 0; i < lineNumber; i++) {
                result += text_string.substr(i * lineLength, lineLength);
                if(i != lineNumber-1) {
                    result += "\n";
                }
            }
            ui_text.ignoreContentAdaptWithSize(isIgnore);
        }
        return result;
    }else {
        return "";
    }
};

jGame.stringToBytes = function ( str ) {
    var ch, st, re = [];
    for (var i = 0; i < str.length; i++ ) {
        ch = str.charCodeAt(i);  // get char
        st = [];                 // set up "stack"
        do {
            st.push( ch & 0xFF );  // push byte to stack
            ch = ch >> 8;          // shift value down by 1 byte
        }
        while ( ch );
        // add stack contents to result
        // done because chars have "wrong" endianness
        re = re.concat( st.reverse() );
    }
    // return an array of bytes
    return re;
}